using System;
using System.Web.UI;
using System.ComponentModel;
using System.Globalization;
using System.Collections.ObjectModel;

namespace Controls
{
    /// <summary>
    /// Represents sequence split item in the <see cref="SequenceItemCollection"/> which
    /// is used to load individual panels in the <see cref="Page"/>.
    /// </summary>
    public abstract class SequenceItem
    {
        /// <summary>
        /// Stores the associated <see cref="SequenceSplitter"/>.
        /// </summary>
        private SequenceSplitter _owner;

        /// <summary>
        /// Stores the associated <see cref="UpdatePanel"/>.
        /// </summary>
        private UpdatePanel updatePanel_;

        /// <summary>
        /// Stores the associated <see cref="UpdateProgress"/>.
        /// </summary>
        private UpdateProgress updateProgress_;

        /// <summary>
        /// Stores the associated <see cref="UpdatePanel"/> ID.
        /// </summary>
        private string associatedUpdatePanelId_;

        /// <summary>
        /// Stores the associated <see cref="UpdateProgress"/> ID.
        /// </summary>
        private string associatedUpdateProgressId_;

        /// <summary>
        /// Stores the load status of the <see cref="Controls.SequenceSplitter"/>.
        /// </summary>
        private bool hasLoaded_;

        /// <summary>
        /// Stores the load priority order.
        /// </summary>
        private LoadPriorityOrder priorityOrder_;

        /// <summary>
        /// Passes through <see cref="SequenceItem(string, string)"/>
        /// </summary>
        protected SequenceItem()
            : this(string.Empty, string.Empty, LoadPriorityOrder.Primary)
        {
        }

        /// <summary>
        /// Passes through <see cref="SequenceItem(string, string, LoadPriorityOrder)"/>
        /// </summary>
        protected SequenceItem(string associatedUpdatePanelId, string associatedUpdateProgressId)
            : this(associatedUpdatePanelId, associatedUpdateProgressId, LoadPriorityOrder.Primary)
        {
        }

        /// <summary>
        /// Creates an instance of <see cref="SequenceItem"/>.
        /// </summary>
        /// <param name="associatedUpdatePanelId">Associated <see cref="UpdatePanel"/> ID.</param>
        /// <param name="associatedUpdateProgressId">Associated <see cref="UpdateProgress"/> ID.</param>
        /// <param name="currentPriorityOrder">Load priority order.</param>
        protected SequenceItem(string associatedUpdatePanelId, string associatedUpdateProgressId, LoadPriorityOrder currentPriorityOrder)
        {
            associatedUpdatePanelId_ = associatedUpdatePanelId;
            associatedUpdateProgressId_ = associatedUpdateProgressId;
            priorityOrder_ = currentPriorityOrder;
        }

        /// <summary>
        /// Gets or sets the load priority order.
        /// </summary>
        public LoadPriorityOrder PriorityOrder
        {
            get
            {
                return priorityOrder_;
            }
            set
            {
                priorityOrder_ = value;
            }
        }

        /// <summary>
        /// Gets or sets the load status of the <see cref="Controls.SequenceSplitter"/>.
        /// </summary>
        protected bool HasLoaded
        {
            get
            {
                return hasLoaded_;
            }
            set
            {
                hasLoaded_ = value;
            }
        }

        /// <summary>
        /// Gets or sets the associated panel.
        /// </summary>
        protected UpdatePanel UpdatePanel
        {
            get
            {
                return updatePanel_;
            }
            set
            {
                updatePanel_ = value;
            }
        }

        /// <summary>
        /// Gets or sets the associated panel.
        /// </summary>
        protected UpdateProgress UpdateProgress
        {
            get
            {
                return updateProgress_;
            }
            set
            {
                updateProgress_ = value;
            }
        }

        /// <summary>
        /// Gets or sets the ID of the <see cref="UpdatePanel"/> control 
        /// that the <see cref="SequenceItem"/> will loading.
        /// </summary>
        [TypeConverter("System.Web.UI.Design.UpdateProgressAssociatedUpdatePanelIDConverter"), 
            Category("Behavior"), DefaultValue(""), IDReferenceProperty(typeof(UpdatePanel))]
        public string AssociatedUpdatePanelID
        {
            get
            {
                if (associatedUpdatePanelId_ == null)
                {
                    return string.Empty;
                }
                return associatedUpdatePanelId_;
            }
            set
            {
                associatedUpdatePanelId_ = value;
            }
        }

        /// <summary>
        /// Gets or sets the ID of the <see cref="UpdateProgress"/> control 
        /// that the <see cref="SequenceItem"/> will be using to display load status.
        /// </summary>
        public string AssociatedUpdateProgressID
        {
            get
            {
                return associatedUpdateProgressId_;
            }
            set
            {
                associatedUpdateProgressId_ = value;
            }
        }

        /// <summary>
        /// Indicates is the loading of the associated panel is completed.
        /// </summary>
        /// <returns>True, if loading of the associated panel is complete, otherwise false.</returns>
        protected internal abstract bool HasLoadCompleted();

        /// <summary>
        /// Initializes the panel and the progress control used by current <see cref="SequenceItem"/>.
        /// </summary>
        protected internal virtual void Initialize()
        {
            UpdatePanel = FindTargetControl(AssociatedUpdatePanelID, true) as UpdatePanel;
            if (!string.IsNullOrEmpty(AssociatedUpdateProgressID))
            {
                UpdateProgress = FindTargetControl(AssociatedUpdateProgressID, true) as UpdateProgress;
            }

        }

        /// <summary>
        /// Performs operations to load the associated <see cref="UpdatePanel"/>.
        /// </summary>
        /// <param name="inProgressSequenceItems">List of <see cref="SequenceItem"/> those
        /// are initiated the load, but has not completed yet.</param>
        protected internal virtual void LoadUpdatePanel(Collection<SequenceItem> inProgressSequenceItems)
        {
        }

        /// <summary>
        /// Sets the owner <see cref="SequenceSplitter"/>,
        /// </summary>
        /// <param name="owner"><see cref="SequenceSplitter"/> to which this 
        /// <see cref="SequenceItem"/> belongs.</param>
        protected internal void SetOwner(SequenceSplitter owner)
        {
            _owner = owner;
        }

        /// <summary>
        /// Gets owner <see cref="SequenceSplitter"/>.
        /// </summary>
        [Browsable(false)]
        public UpdatePanel Owner
        {
            get
            {
                return _owner;
            }
        }

        /// <summary>
        /// See <see cref="FindTargetControl(string, Control, bool)"/>.
        /// </summary>
        protected Control FindTargetControl(string controlId, bool searchNamingContainers)
        {
            if (string.IsNullOrEmpty(controlId))
            {
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, string.Empty, new object[] { Owner.ID, }));
            }
            Control control = FindTargetControl(controlId, Owner, searchNamingContainers);
            if (control == null)
            {
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, string.Empty, new object[] { controlId, Owner.ID }));
            }
            return control;
        }

        /// <summary>
        /// Finds the target control based on the control ID.
        /// </summary>
        /// <param name="controlID">ID of the control to search for.</param>
        /// <param name="control">Control, which is used as the reference control tree,
        /// to perform search for any target control based on a control ID.</param>
        /// <param name="searchNamingContainers">True, if the <see cref="System.Web.UI.Control.NamingContainers"/>
        /// to be searched, otherwise false.</param>
        /// <returns>The target control instance based on the ID.</returns>
        static internal Control FindTargetControl(string controlID, Control control, bool searchNamingContainers)
        {
            if (searchNamingContainers)
            {
                Control namingContainer = control;
                Control control2 = null;
                while ((control2 == null) && (namingContainer != control.Page))
                {                    
                    namingContainer = namingContainer.NamingContainer;
                    if (namingContainer == null)
                    {
                        return control2;
                    }
                    control2 = namingContainer.FindControl(controlID);
                }
                return control2;
            }
            return control.FindControl(controlID);
        }

    }
}

    /// <summary>
    /// Load priority order, based on which the panels will be sequenced
    /// for loading operation.
    /// </summary>
    public enum LoadPriorityOrder
    {
        /// <summary>
        /// Loaded as priority item.
        /// </summary>
        Primary,
        /// <summary>
        /// Loaded after the <see cref="LoadPriorityOrder.Primary"/> items.
        /// </summary>
        Secondary,
        /// <summary>
        /// Loaded after the <see cref="LoadPriorityOrder.Secondary"/> items.
        /// </summary>
        Tertiary
    }

